package parser

import (
	"fmt"
	"fox/src/ast"
	"fox/src/lexer"
)

const (
	_ int = iota
)

type Parser struct {
	l         *lexer.Lexer
	curToken  lexer.Token
	peekToken lexer.Token

	errors []string
}

func New(l *lexer.Lexer) *Parser {
	p := &Parser{l: l, errors: []string{}}

	// Read two tokens, so curToken and peekToken are both set
	p.nextToken()
	p.nextToken()

	return p
}

func (p *Parser) nextToken() {
	p.curToken = p.peekToken
	p.peekToken = p.l.NextToken()
}

func (p *Parser) curTokenIs(t lexer.TokenType) bool {
	return p.curToken.Type == t
}

func (p *Parser) peekTokenIs(t lexer.TokenType) bool {
	return p.peekToken.Type == t
}

// 判断下一个token是否正确，并执行下一个token
func (p *Parser) expectPeek(t lexer.TokenType) bool {
	if p.peekTokenIs(t) {
		p.nextToken()
		return true
	} else {
		// 下一个token错误
		p.peekError(t)
		return false
	}
}

// 错误数组
func (p *Parser) Errors() []string {
	return p.errors
}

// 下一个token错误
func (p *Parser) peekError(t lexer.TokenType) {
	msg := fmt.Sprintf("下一个Token应为 '%s' ,而得到的却是 '%s':'%s'",
		t, p.peekToken.Type, p.peekToken.Literal)
	p.errors = append(p.errors, msg)
}

// 抛出错误
func (p *Parser) throwError(msg string) {
	p.errors = append(p.errors, msg)
}

// 解析程序
func (p *Parser) ParseProgram() *ast.Program {
	// 创建一个ast.Program类型的变量program
	program := &ast.Program{}
	//循环解析语句
	for !p.curTokenIs(lexer.EOF) {
		stmt := p.parseStatement()
		if stmt != nil {
			program.Statements = append(program.Statements, stmt)
		}
		p.nextToken()
	}

	return program
}

// 解析语句
func (p *Parser) parseStatement() ast.Statement {
	// 根据当前token的类型，调用相应的解析函数
	switch p.curToken.Type {
	case lexer.LET:
		// 解析let语句
		return p.parseLetStatement()
	/* case lexer.RETURN:
	// 解析return语句
	return p.parseReturnStatement() */
	default:
		// 默认返回nil
		return nil
	}
}

func (p *Parser) parseLetStatement() *ast.LetStatement {
	stmt := &ast.LetStatement{Token: p.curToken}
	if !p.expectPeek(lexer.IDENT) {
		p.throwError("语法错误无效的标识符")
		return nil
	}
	//变量名称
	stmt.Name = &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal}
	if !p.expectPeek(lexer.ASSIGN) {
		p.throwError("语法错误无效的赋值")
		return nil
	}
	p.nextToken()
	return stmt
}
